{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# chap9 类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**面对对象编程** 是最有效的软件编写方法之一。在面向对象编程中，你编写表示现实世界中的事物和情景的类，并基于这些类来创建对象。编写类时，你定义一大类对像都有的通用行为。基于类创建对象时，每个对象都自动具备这种通用行为，然后可根据需要赋予每个对象独特的个性。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "根据类来创建对象被称为**实例化**，这让你能够使用类的实例。这本章中，你将编写一些类并创建其实例。你将指定可在实例中存储什么信息，定义可对这些实例执行那些操作。你将编写一些类来扩展既有类的功能，让相似的类能够高效地共享代码。你将把自己编写的类存储在模块中，并在自己的程序文件中导入其他程序员编写的类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "理解面向对象编程有助于你像程序员那样看世界，还可以帮助你真正明白自己编写的代码"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.1 创建和使用类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "class关键字创建类。这里需要注意的地方很多，但你也不用担心，本章充斥着这样的结构，你有大把的机会熟悉它。\n",
    "名称指的是类。这个类定义中的括号是空的，因为我们要从空白创建这个类。**类的名称一般是首字母大写**\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Dog():\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "    \n",
    "    def sit(self):\n",
    "        print(self.name.title() + \" is now sitting.\")\n",
    "    \n",
    "    def roll(self):\n",
    "        print(self.name.title() + \" rolled over!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\\_\\_init\\_\\_()就是初始化类。我是将name和age初始化。 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后定义了两个类函数：sit() and roll()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dog = Dog('doom', 12)  # 创建一个实例对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Doom is now sitting.\n"
     ]
    }
   ],
   "source": [
    "my_dog.sit()  # 使用实例对象中的sit()方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个实例对象后，就可以使用类方法了。当然也可以查看实例属性，若没有定义为私有属性的话，甚至可以更改实例属性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'doom'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_dog.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dog.name = 'honey'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'honey'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_dog.name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.2 使用类和实例"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你可以根据类来模拟现实世界中的很多情景。类编号后， 你大部分时间将花在使用类创建的实例上。你需要执行的一个重要操作就是修改实例的属性。你可以直接修改，也可以编写特定的方法修改。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 9.2.1 Car类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Audi A4\n"
     ]
    }
   ],
   "source": [
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    \n",
    "    def __init__(self, make, model, year):\n",
    "        \"\"\"初始化描述汽车的属性\"\"\"\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        \n",
    "    def get_descriptive_name(self):\n",
    "        \"\"\"返回整洁的描述性信息\"\"\"\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    \n",
    "my_new_car = Car('audi', 'a4', 2016)\n",
    "print(my_new_car.get_descriptive_name())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个Car类和Dog类大同小异，如果你之前看懂了，那么这个就会很简单。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 9.2.2 为类添加默认值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "每个实例在创建时都会初始化。但有时我们不需要用户定义所有属性值。这是就要为类添加默认值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Audi A4\n",
      "This car has 0 miles on it.\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    \n",
    "    def __init__(self, make, model, year):\n",
    "        \"\"\"初始化描述汽车的属性\"\"\"\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "        \n",
    "    def get_descriptive_name(self):\n",
    "        \"\"\"返回整洁的描述性信息\"\"\"\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    \n",
    "    def read_odometer(self):\n",
    "        \"\"\"打印一条指出汽车里程的消息\"\"\"\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "\n",
    "my_new_car = Car('audi', 'a4', 2016)\n",
    "print(f'{my_new_car.get_descriptive_name()}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 9.2.3 修改属性值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第一种是直接修改"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2021"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_new_car.year = 2021\n",
    "my_new_car.year"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第二种是通过方法修改"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This car has 0 miles on it.\n",
      "This car has 20 miles on it.\n"
     ]
    }
   ],
   "source": [
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    \n",
    "    def __init__(self, make, model, year):\n",
    "        \"\"\"初始化描述汽车的属性\"\"\"\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "        \n",
    "    def get_descriptive_name(self):\n",
    "        \"\"\"返回整洁的描述性信息\"\"\"\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    \n",
    "    def read_odometer(self):\n",
    "        \"\"\"打印一条指出汽车里程的消息\"\"\"\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "    \n",
    "    def update_odometer(self, odometer):\n",
    "        \"\"\"修改汽车里程\"\"\"\n",
    "        self.odometer_reading = odometer\n",
    "        \n",
    "my_new_car = Car('audi', 'a4', 2016)\n",
    "my_new_car.read_odometer()\n",
    "my_new_car.update_odometer(20)\n",
    "my_new_car.read_odometer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.3 继承"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "编写类的时候，并非都是从0开始的。如果你要编写的类时另一个类的特殊版本，则你就可以使用**继承**。它会自动获取所有的方法和属性。原有的类被称为**父类**，新类被称为**子类**。子类继承父类所有的属性和方法，当然也可定义其他的属性和方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 9.3.1 子类的\\_\\_init\\_\\_方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ElectricCar(Car):\n",
    "    \"\"\"电动汽车的独特之处\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        \"\"\"初始化父类的属性\"\"\" \n",
    "        super().__init__(make, model, year)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ElectricCar这个类继承了Car类，他拥有Car类所有的属性和方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This car has 0 miles on it.\n"
     ]
    }
   ],
   "source": [
    "my_electriccar = ElectricCar('audi', 'a4', 2020)\n",
    "my_electriccar.read_odometer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 9.3.2 定义子类的属性和方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "让一个类继承另一个类后，可添加区分子类和父类所需的新属性和方法。<br></br>\n",
    "下面来添加一个电动汽车特有的属性（电瓶），以及一个描述该属性的方法。我们将存储电瓶容量，并编写一个打印电瓶描述的方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Tesla Model S\n",
      "This car have a 70-kWh battery.\n"
     ]
    }
   ],
   "source": [
    "class ElectricCar(Car):\n",
    "    def __init__(self, make, model, year):\n",
    "        super().__init__(make, model, year)\n",
    "        self.battery_size = 70\n",
    "    \n",
    "    def describe_battery(self):\n",
    "        print(f\"This car have a {self.battery_size}-kWh battery.\")\n",
    "\n",
    "my_tesla = ElectricCar('tesla', 'model s', 2016)\n",
    "print(my_tesla.get_descriptive_name())\n",
    "my_tesla.describe_battery()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 9.3.3 重写父类和方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python解释器采取的是就近原则。只要和父类的方法重名即可。如果你想使用父类方法可以使用：super().function_name()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 9.3.4 将实例用作属性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用类模拟实物时，你可能会发现给类添加的细节越来越多。在这种情况下，你可能就会将这个类的一部分作为一个独立的类提取出来，从而将一个大类拆分成若干小类。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This car has a 70-kWh battery.\n"
     ]
    }
   ],
   "source": [
    "class Battery():\n",
    "    \"\"\"一次模拟电动汽车电瓶的简单尝试\"\"\"\n",
    "    def __init__(self, battery_size=70):\n",
    "        \"\"\"初始化电瓶的属性\"\"\"\n",
    "        self.battery_size = battery_size\n",
    "    def describe_battery(self):\n",
    "        \"\"\"打印一条描述电瓶容量的消息\"\"\"\n",
    "        print(\"This car has a \" + str(self.battery_size) + \"-kWh battery.\")\n",
    "\n",
    "class ElectricCar(Car):\n",
    "    \"\"\"电动汽车的独特之处\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        \"\"\" 初始化父类的属性，再初始化电动汽车特有的属性\n",
    "        \"\"\"\n",
    "        super().__init__(make, model, year) \n",
    "        self.battery = Battery()\n",
    "\n",
    "my_tesla = ElectricCar('tesla', 'model s', 2020)\n",
    "my_tesla.battery.describe_battery()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我是将一个ElectricCar分开了，其中将Battery类实例化了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这样会使代码看起来整齐有序，有助于阅读和维护。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.4 导入类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Audi A4\n",
      "This car has 23 miles on it.\n"
     ]
    }
   ],
   "source": [
    "from car import Car\n",
    "\n",
    "my_new_car = Car('audi', 'a4', 2016)\n",
    "print(my_new_car.get_descriptive_name())\n",
    "my_new_car.odometer_reading = 23\n",
    "my_new_car.read_odometer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "用from ... import ...和import导入 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Volkswagen Beetle\n"
     ]
    }
   ],
   "source": [
    "import car\n",
    "my_beetle = car.Car('volkswagen', 'beetle', 2016)\n",
    "print(my_beetle.get_descriptive_name())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 9.4.1 在一个模块中导入另一个模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有时候，模块直接不是独立的，是相互调用的。因此在导入一个模块时就需要导入另一模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Tesla Roadster\n"
     ]
    }
   ],
   "source": [
    "from electric_car import ElectricCar\n",
    "# my_beetle = Car('volkswagen', 'beetle', 2016)\n",
    "# print(my_beetle.get_descriptive_name())\n",
    "my_tesla = ElectricCar('tesla', 'roadster', 2016)\n",
    "print(my_tesla.get_descriptive_name())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 9.4.2 自定义流程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "正如你看到的，在组织大型项目的代码方面，Python提供了很多选项。熟悉所有这些选项很重要，这样你才能确定哪种项目组织方式是最佳的，并能理解别人开发的项目。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一开始应让代码结构尽可能简单。先尽可能在一个文件中完成所有的工作，确定一切都能正确运行后，再将类移到独立的模块中。如果你喜欢模块和文件的交互方式，可在项目开始时就尝试将类存储到模块中。先找出让你能够编写出可行代码的方式，再尝试让代码更为组织有序。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.5 小结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在本章中，你学习了：\n",
    "1. 如何编写类；\n",
    "2. 如何使用属性在类中存储信息，以及如何编写方法，以让类具备所需的行为；\n",
    "3. 如何编写方法__init__() ，以便根据类创建包含所需属性的实例。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你见识了如何修改实例的属性——包括直接修改以及通过方法进行修改。你还了解了：使用继承可简化相关类的创建工作；将一个类的实例用作另一个类的属性可让类更简洁。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
